﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using System.Collections.ObjectModel;
using System.Xml;
using System.Xml.XPath;
using System.Reflection;
using System.Threading;

using log4net;
using System.Xml;
using System.Xml.XPath;

using CommonLib;

namespace ConfigUtilLib
{
    public class ProcessorRecord
    {
        private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
        private const string InterfaceStr = "CommonLib.ProcessInterface";

        private const string NameStr = "name";                
        private const string ProcessorConfigurationFileStr = "processorConfigurationFile";
        private const string FetcherAssociationStr = "FetcherAssociation";
        private const string AssemblyDllStr = "DLL";
        private const string ActiveAttrString = "active";

        public string ProcessorName { get; private set; }
        public string AssemblyDllName { get; private set; }
        public string ProcessConfigFile { get; private set; }
        public bool IsActive { get; private set; }
        public string FetcherAssociation { get; private set; }
        public ProcessorConfigBaseRec ProcessorConfig { get; private set; }


        public bool LoadConfiguration(FetcherAndProcessorBin processorBinRec , XmlNode processorCfgNode)
        {

            Console.Write("Reading Processor Data ");
            //1.  Get The name of the processor and dir 
            if (processorCfgNode.Attributes != null)
            {
                var xmlAttr = processorCfgNode.Attributes[NameStr];

                if (xmlAttr == null)
                {
                    return false;
                }

                ProcessorName = xmlAttr.Value;
                log.DebugFormat("Processor Name: "+ProcessorName);

                //2.  Get  Active /Inactive Flag

                xmlAttr = processorCfgNode.Attributes[ActiveAttrString];

                if (xmlAttr == null)
                {
                    return false;
                }

                IsActive = System.Convert.ToBoolean(xmlAttr.Value);
            }
            log.DebugFormat("Active Flag : " + IsActive);


            //3.  Get DLL 

            if (processorBinRec == null)
            {
                log.ErrorFormat("Processor DLL Configuration Missing , May be Type=\"BlahBlah\" is missing ");
                return false;
            }

            AssemblyDllName = processorBinRec.Dll;
         

            log.DebugFormat("Processor DLL  :{0}", AssemblyDllName);



            //4. get Assembly ConfigurationFile 

            var processorConfigFileNameNode = processorCfgNode.SelectSingleNode(ProcessorConfigurationFileStr);
            if (processorConfigFileNameNode != null)
            {
                ProcessConfigFile = processorConfigFileNameNode.InnerText; 
            }
            log.DebugFormat("Processor Configuration File  Name : " + ProcessConfigFile);

            // 5. get fetcher association string 
            var fetcherAssociationNode = processorCfgNode.SelectSingleNode(FetcherAssociationStr);
            if (fetcherAssociationNode != null)
            {
                FetcherAssociation = fetcherAssociationNode.InnerText; 
            }
            log.DebugFormat("Processor Fetcher Association String : " + FetcherAssociation);


            // Finally Letting DLL to read optional Params 
            ProcessorConfig = null;
            ProcessorConfig = getConfiguration( processorBinRec ,  processorCfgNode);
            log.DebugFormat("Completed Reading Processor data for :" + ProcessorName);
            return true;
        }


        private ProcessorConfigBaseRec getConfiguration(FetcherAndProcessorBin processorBinRec, XmlNode processorCfgNode)
        {
            log.DebugFormat(" Configuration reading by {0}  , DLL is {1} ", processorBinRec.Type, processorBinRec.Dll);

            // Loop thru Everey Process Object 
            Assembly reflectionAssembly = null;
            ProcessorConfigBaseRec processorConfig = null;

            try
            {
                // 1. Load Library 
                reflectionAssembly = Assembly.LoadFrom(processorBinRec.Dll);
            }
            catch (Exception e)
            {
                log.DebugFormat("Unable to Load DLL : {0} : {1}", processorBinRec.Dll, e.Message);
                return null;
            }

            if (reflectionAssembly == null) return null;

            foreach (Type classType in reflectionAssembly.GetTypes())
            {

                // 2. Verify Credentials  

                if ((classType == null) || (classType.IsClass != true) || (classType.GetInterface(InterfaceStr) == null))
                {
                    continue;
                }

                // if all good Invoke The method 
                var ibaseObject = Activator.CreateInstance(classType) as ProcessInterface;
                log.DebugFormat("......Dynamically Invoking compute() on {0} Class  ", classType.FullName);

                // Kick it off in a Thread.. 
                if (ibaseObject != null) processorConfig = ibaseObject.getConfiguration(processorCfgNode);
            }

            return processorConfig;

        }
    }
}
